#ifndef CORE_UTILITY_H
#define CORE_UTILITY_H
#include <glm\glm.hpp>
#include <random>
namespace RayTracer
{
	const float infinity = std::numeric_limits<float>::infinity();
	//const float PI = 3.141592f;
	inline float Random01() 
	{
		static std::uniform_real_distribution<float> distribution(0.0, 1.0);
		static std::mt19937 generator;
		return distribution(generator);
	}

	inline float RandomX2Y(float min, float max) {
		return min + (max - min)*Random01();
	}


	inline float clamp(float x, float min, float max) 
	{
		if (x < min) return min;
		if (x > max) return max;
		return x;
	}

	inline vec3 RandomDir() {
		return vec3(Random01(), Random01(), Random01());
	}

	inline vec3 RandomDir(double min, double max) {
		return vec3(RandomX2Y(min, max), RandomX2Y(min, max), RandomX2Y(min, max));
	}

	inline vec3 RandomSphere() 
	{
		while (true) 
		{
			auto p = RandomDir(-1, 1);
			if (glm::dot(p,p) >= 1) continue;
			return p;
		}
	}

	inline vec3 RandomHemiSphere(const vec3& normal) 
	{
		vec3 in_unit_sphere = RandomSphere();
		if (dot(in_unit_sphere, normal) > 0.0)
			return in_unit_sphere;
		else
			return -in_unit_sphere;
	}

	inline void GammaCorrect(vec3& color) 
	{
		color.r = sqrt(color.r);
		color.g = sqrt(color.g);
		color.b = sqrt(color.b);
	}

	inline bool CloseZore(const vec3& e)
	{
		const auto s = 1e-8;
		return (fabs(e[0]) < s) && (fabs(e[1]) < s) && (fabs(e[2]) < s);
	}

	inline vec3 RandomVector() 
	{
		return glm::normalize(RandomSphere());
	}

	inline vec3 RandomDisk() 
	{
		while (true) 
		{
			auto p = vec3(RandomX2Y(-1, 1), RandomX2Y(-1, 1), 0);
			if (dot(p,p) >= 1) continue;
			return p;
		}
	}

	inline int RandomInt(int min, int max)
	{
		return static_cast<int>(RandomX2Y(min, max + 1));
	}
}
#endif // !CORE_UTILITY_H
